package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"regexp"
	"strings"
	"time"
)

var fileName string

const maxNum = 3

func parseLine(in string) []string {
	var ret []string
	tmp := ""
	started := false
	for i := 0; i < len(in); i++ {
		if started {
			if in[i] == '"' || in[i] == '[' || in[i] == ']' {
				started = false
			} else {
				tmp += string(in[i])
			}
		} else {
			if in[i] == '"' || in[i] == '[' || in[i] == ']' {
				started = true
				continue
			} else if in[i] == ' ' {
				ret = append(ret, tmp)
				tmp = ""
				continue
			} else {
				tmp += string(in[i])
			}
		}
	}
	if tmp != "" {
		ret = append(ret, tmp)
	}
	return ret
}

var startTime time.Time
var endTime time.Time

func init() {
	flag.StringVar(&fileName, "f", "access.log", "access.log file name")
	flag.Parse()

	startTime, _ = time.Parse("2/Jan/2006:15:04:05 -0700", "03/May/2012:00:00:00 -0700")
	endTime, _ = time.Parse("2/Jan/2006:15:04:05 -0700", "22/May/2012:00:00:00 -0700")
}

func getUrl(in string) string {
	b, _ := regexp.MatchString("^[a-zA-Z0-9\\-_]{1,}\\.[a-zA-Z0-9\\-_]{1,}$", in)
	if b {
		return in
	}
	index := strings.Index(in, "+http")
	if index > 0 {
		r := in[index:]
		r = strings.Replace(r, "+http://", "", 1)
		r = strings.Replace(r, "+https://", "", 1)
		index = strings.Index(r, "/")
		if index > 0 {
			r = r[:index]
		}
		r = strings.Trim(r, "()")
		return r
	}
	return ""
}

func compute(um UserMap, ip string) (*Result, error) {
	var ret Result
	u, found := um[ip]
	if !found {
		return nil, fmt.Errorf("IP不存在")
	}
	for tmpIp, domain := range um {
		if tmpIp == ip {
			continue
		}
		merge := make(map[string]bool)
		for k := range u {
			merge[k] = true
		}
		common := make(map[string]bool)
		for k := range domain {
			if u[k] {
				common[k] = true
			}
		}
		s := float64(len(common)) / float64(len(merge))
		if len(ret.Ip) > 0 {
			if s > ret.Score {
				ret.Ip = []string{tmpIp}
				ret.Score = s
			} else if s == ret.Score {
				ret.Ip = append(ret.Ip, tmpIp)
			}
		} else {
			ret.Ip = []string{tmpIp}
			ret.Score = s
		}
	}
	return &ret, nil
}

func main() {
	f, err := os.Open(fileName)
	if err != nil {
		panic(err)
	}
	defer f.Close()
	reader := bufio.NewReader(f)

	ipMap := make(map[string]int)
	countMap := make(map[string]int) // 统计访问域名的次数 www.bing.com
	userMap := make(UserMap)
	for line, _, err := reader.ReadLine(); err == nil; line, _, err = reader.ReadLine() {
		l := string(line)
		data := parseLine(l)

		tt, errTime := time.Parse("2/Jan/2006:15:04:05 -0700", data[3])
		if errTime != nil {
			//无效时间格式
			fmt.Println(errTime)
			continue
		}
		ip := data[0]
		//fmt.Println(tt)
		ipMap[ip] += 1
		u := data[len(data)-2]
		if strings.Contains(u, "www.bing.com") {
			if tt.After(startTime) && tt.Before(endTime) {
				countMap[ip] += 1
			}
		}
		u = getUrl(data[len(data)-2])
		if u != "" {
			if _, ok := userMap[ip]; ok {
				userMap[ip][u] = true
			} else {
				userMap[ip] = make(map[string]bool)
				userMap[ip][u] = true
			}
		}
	}
	fmt.Println("独立IP数: ", len(ipMap))
	//fmt.Println(countMap)
	//fmt.Println(ipMap)
	heap := NewHeap(maxNum)
	for ip, v := range countMap {
		heap.Push(IpNode{
			Ip:  ip,
			Num: v,
		})
	}
	//访问 www.bing.com 次数最多的n个IP
	fmt.Println("访问 www.bing.com 次数最多的IP:")
	for heap.length > 0 {
		node := heap.Pop()
		fmt.Printf("IP: %s Num: %d \n", node.Ip, node.Num)
	}
	var inputIp string
	fmt.Println("请输入IP:")
	_, err = fmt.Scanf("%s", &inputIp)
	if err != nil {
		fmt.Println(err)
		return
	}
	result, err := compute(userMap, inputIp)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("最相近的IP: ")
		for _, ip := range result.Ip {
			fmt.Println(ip)
		}
		fmt.Println("最大s值s:", result.Score)
	}
}
